﻿#include "EditorReflectedPropertyView.h"

#include "Widgets/EditorCheckBoxWidget.h"
#include "Widgets/Widget.h"
#include "Widgets/TextWidget.h"
#include "Widgets/EditorDragableSpinWidget.h"
#include "Widgets/Positioners/VerticalPositionerWidget.h"
#include "Widgets/Window.h"
#include "Widgets/RootWidget.h"
#include "Widgets/RectangleWidget.h"

#include "Property/ReflectedProperty/EditorReflectedPropertyViewModel.h"
#include "Widgets/EditorAssetSelectorWidget.h"

#include "Mesh/StaticMesh.h"
#include "Material/Material.h"

#include "Framework/Editor.h"
#include "Theme/EditorTheme.h"
#include "Asset/EditorDefaultPackage.h"
#include "Window/EditorWindowGroupViewModel.h"

#include "Window/EditorPopupMenuView.h"
#include "Window/EditorWindowGroupView.h"

void REditorReflectedPropertyView::BindViewModel(TSharedObjectPtr<REditorPropertyViewModel> InViewModel)
{
    Super::BindViewModel(InViewModel);
    PropertyViewModel=InViewModel;

    PropertyViewModel->OnListChanged.Bind([this]()
    {
        UpdateListContent();
    });
}

void REditorReflectedPropertyView::CreateWidget(TSharedObjectPtr<RVerticalPositionerWidget> InValueList)
{
    auto Root=NewWidget<RWidget>(InValueList);
    Root->Anchor.HorizontalFill(InValueList);
    Root->Height=
    [this]()
    {
        return PropertyViewModel->GetListHeight();
    };
 
    List=NewWidget<RVerticalPositionerWidget>(Root);
    List->Anchor.Fill(Root);
    List->Spacing=0;

    UpdateListContent();
}

void REditorReflectedPropertyView::UpdateListContent()
{
    if(!List.IsValid())
    {
        return;
    }

    List->ClearSubWidgets();
    

    for(int64_t i=0; i<PropertyViewModel->GetLineItemNum(); ++i)
    {
        auto PropertyType=PropertyViewModel->GetViewType(i);

        auto Line=NewWidget<RWidget>(List);
        Line->Anchor.HorizontalFill(List);
        Line->Height=PropertyViewModel->GetLineHeight(i);

        const float ExpandIconWidth=20;
        if(PropertyViewModel->HasExpandIcon(i))
        {   

            auto ExpandIcon=NewWidget<RImageWidget>(Line);
            ExpandIcon->Width=ExpandIconWidth;
            ExpandIcon->Height=ExpandIconWidth;
            ExpandIcon->Anchor.VerticalCenterReference=Line;
            ExpandIcon->Anchor.LeftReference=Line;
            ExpandIcon->Anchor.LeftOffset=PropertyViewModel->GetDepth(i);
            ExpandIcon->Image=PropertyViewModel->GetExpandIcon(i);
            auto ExpandIconMouse=NewWidget<RMouseWidget>(ExpandIcon);
            ExpandIconMouse->Anchor.Fill(ExpandIcon);
            ExpandIconMouse->OnClicked.BindLambda([this,i](const SMouseButtonEvent&)
            {
                PropertyViewModel->ToggleExpand(i);
                return true;
            });
        }

        auto NameWidget=NewWidget<RTextWidget>(Line);
        NameWidget->Text=PropertyViewModel->GetPropertyName(i);
        NameWidget->Anchor.VerticalFill(Line); 
        NameWidget->Anchor.LeftReference=Line;
        NameWidget->Anchor.LeftOffset=PropertyViewModel->GetDepth(i) + ExpandIconWidth;
        NameWidget->Width=
            [this, i,ExpandIconWidth]()
            {
                return PropertyViewModel->GetSpliterLeftOffset()-PropertyViewModel->GetDepth(i)-ExpandIconWidth;
            };
        NameWidget->VerticalAlignment=ETextVerticalAlignment::Center;

        const float MoreButtonWidth=20;
        if(PropertyViewModel->HasMoreOperationButton(i))
        {
            auto MoreButton=NewWidget<RRectangleWidget>(Line);
            MoreButton->Width=MoreButtonWidth;
            MoreButton->Height=PropertyViewModel->LineHeight;
            MoreButton->Anchor.VerticalFill(Line);
            MoreButton->Anchor.RightReference=Line;
            MoreButton->Anchor.RightOffset=0;
            MoreButton->FillColor=REditor::Get()->CurrentTheme->ImageButtonHovorColor;

            auto MoreButtonImage=NewWidget<RImageWidget>(MoreButton);
            MoreButtonImage->Width=MoreButtonWidth;
            MoreButtonImage->Height=MoreButtonWidth;
            MoreButtonImage->Image= REditorDefaultPackage::Get()->
                GetIcon(U"CodiconEllipsis");
            MoreButtonImage->Anchor.CenterIn(MoreButton);

            auto MoreButtonMouse=NewWidget<RMouseWidget>(MoreButton);
            MoreButtonMouse->Anchor.Fill(MoreButton);
            RMouseWidgetWeakPtr MoreButtonMouseWeak=MoreButtonMouse;
            MoreButton->Fill=[MoreButtonMouseWeak](){
                return MoreButtonMouseWeak->IsHovered();
            };
            MoreButtonMouse->OnClicked.BindLambda([this,MoreButtonMouseWeak,i](const SMouseButtonEvent& InEvent){
                //create a context menu
                TVector<SEditorContextMenuLine> RootContextMenu;

                if(PropertyViewModel->CanDelete(i))
                {
                    auto& Delete= RootContextMenu.Emplace();
                    Delete.Text=U"删除";
                    Delete.OnClicked.Bind([this,i](){
                        PropertyViewModel->Delete(i);
                    });
                }

                if(PropertyViewModel->CanInsert(i))
                {
                    auto& Insert= RootContextMenu.Emplace();
                    Insert.Text=U"插入";
                    Insert.OnClicked.Bind([this,i](){
                        PropertyViewModel->Insert(i);
                    });
                }

                if(PropertyViewModel->CanDuplicate(i))
                {
                    auto& Duplicate= RootContextMenu.Emplace();
                    Duplicate.Text=U"复制";
                    Duplicate.OnClicked.Bind([this,i](){
                        PropertyViewModel->Duplicate(i);
                    });
                }

                REditorWindowGroupViewModel::Get()->ShowContextMenu(
                RootContextMenu
                ,MoreButtonMouseWeak
                ,150
                );

                return true;

            });
        }

        float ValuePadding=5;
        auto ValueParent=NewWidget<RWidget>(Line);
        ValueParent->Anchor.VerticalFill(Line);
        ValueParent->Anchor.LeftReference=NameWidget;
        ValueParent->Anchor.LeftReferenceEdge=EHorizontalWidgetEdge::Right;
        ValueParent->Anchor.LeftOffset=
            PropertyViewModel->SpliterWidth
            + ValuePadding
            ;
        ValueParent->Anchor.RightReference=Line;
        ValueParent->Anchor.RightOffset=ValuePadding + MoreButtonWidth;

        if (PropertyType == REditorReflectedPropertyViewModel::EPropertyType::Int64)
        {
            auto Value=NewWidget<REditorDragableSpinWidget>(ValueParent);
            Value->Anchor.Fill(ValueParent);
            Value->IsInteger=true;
            Value->Value= [this,i]()->float
            {
                return PropertyViewModel->GetIntValue(i);
            };
            Value->OnAccepted.BindLambda([this,i](ETextEditStopReason Reason,float Value )
            {
                if(Reason==ETextEditStopReason::Cancel)
                {
                    return;
                }

                PropertyViewModel->SetIntValue(i, Value);
            });
        }
        else if(PropertyType == REditorReflectedPropertyViewModel::EPropertyType::Float)
        {
            auto Value=NewWidget<REditorDragableSpinWidget>(ValueParent);
            Value->Anchor.Fill(ValueParent);
            Value->IsInteger=false;
            Value->Value= [this,i]()->float
            {
                return PropertyViewModel->GetFloatValue(i);
            };
            Value->OnAccepted.BindLambda([this,i](ETextEditStopReason Reason,float Value )
            {
                if(Reason==ETextEditStopReason::Cancel)
                {
                    return;
                }

                PropertyViewModel->SetFloatValue(i,Value);
            });        
        }
        else if(PropertyType == REditorReflectedPropertyViewModel::EPropertyType::Bool)
        {
            auto Value=NewWidget<REditorCheckBoxWidget>(ValueParent);
            Value->Width=PropertyViewModel->LineHeight;
            Value->Height=PropertyViewModel->LineHeight;
            Value->CheckState=[this,i]()->ECheckBoxWidgetState
            {
                return PropertyViewModel->GetBoolValue(i)?ECheckBoxWidgetState::Checked:ECheckBoxWidgetState::Unchecked;
            };
            Value->OnCheckStateChanged.Bind([this,i](ECheckBoxWidgetState State)
            {
                PropertyViewModel->SetBoolValue(i,State==ECheckBoxWidgetState::Checked);
            });
        }
        else if(PropertyType == REditorReflectedPropertyViewModel::EPropertyType::String)
        {
            auto Value=NewWidget<REditableTextWidget>(ValueParent);
            Value->Anchor.Fill(ValueParent);
            Value->Text=[this,i]()->CString
            {
                return PropertyViewModel->GetStringValue(i);
            };
            Value->OnEditStopped.BindLambda([this,i](ETextEditStopReason Reason,const CString& Text)
            {
                if(Reason==ETextEditStopReason::Cancel)
                {
                    return;
                }
                PropertyViewModel->SetStringValue(i,Text);
            });
        }
        else if(PropertyType == REditorReflectedPropertyViewModel::EPropertyType::StaticMesh)
        {
            auto Value=NewWidget<RWidget>(ValueParent);
            Value->Anchor.Fill(ValueParent);
            RWidgetWeakPtr ValueWeak=Value;

            auto Name=NewWidget<RTextWidget>(Value);
            Name->Anchor.VerticalFill(Value);
            Name->Text=[this,i]()->CString
            {
                TSharedObjectPtr<RStaticMesh> Mesh=PropertyViewModel->
                    GetStaticMeshValue(i);
                if(Mesh)
                {
                    return Mesh->GetNodeName();
                }
                return U"";
            };
            Name->VerticalAlignment=ETextVerticalAlignment::Center;

            auto ComboBoxIcon=NewWidget<RImageWidget>(Value);
            ComboBoxIcon->Anchor.RightReference=Value;
            ComboBoxIcon->Width=PropertyViewModel->LineHeight;
            ComboBoxIcon->Height=PropertyViewModel->LineHeight;
            ComboBoxIcon->Image=
                REditorDefaultPackage::Get()->GetIcon(U"CodiconChevronDown");

            Name->Anchor.RightReference=ComboBoxIcon;
            Name->Anchor.RightOffset=5;
            Name->Anchor.RightReferenceEdge=EHorizontalWidgetEdge::Left;

            auto Mouse=NewWidget<RMouseWidget>(Value);
            Mouse->Anchor.Fill(Value);
            Mouse->OnClicked.BindLambda([this,i,ValueWeak](const SMouseButtonEvent&)
            {
                //open asset selector
                SIntPoint PopupSize;
                PopupSize.X=300;
                PopupSize.Y=400;
                auto SelectorParent=REditorWindowGroupView::Get()->CreatePopupMenu(
                    PopupSize
                    ,ValueWeak
                );

                auto Selector=NewWidget<REditorAssetSelectorWidget>(SelectorParent);
                Selector->Anchor.Fill(SelectorParent);
                Selector->OnAssetSelected.Bind([this,i](TSharedObjectPtr<RObject> Mesh)
                {
                    PropertyViewModel->SetStaticMeshValue(i,Mesh);
                });
                Selector->SetAssetType(EEditorSelectableAssetType::StaticMesh);


                return true;
            });



        }
        else if(PropertyType == REditorReflectedPropertyViewModel::EPropertyType::Material)
        {
            auto Value=NewWidget<RWidget>(ValueParent);
            Value->Anchor.Fill(ValueParent);
            RWidgetWeakPtr ValueWeak=Value;

            auto Name=NewWidget<RTextWidget>(Value);
            Name->Anchor.VerticalFill(Value);
            Name->Text=[this,i]()->CString
            {
                TSharedObjectPtr<RMaterial> Material=PropertyViewModel->
                    GetMaterialValue(i);
                if(Material)
                {
                    return Material->GetNodeName();
                }
                return U"";
            };
            Name->VerticalAlignment=ETextVerticalAlignment::Center;

            auto ComboBoxIcon=NewWidget<RImageWidget>(Value);
            ComboBoxIcon->Anchor.RightReference=Value;
            ComboBoxIcon->Width=PropertyViewModel->LineHeight;
            ComboBoxIcon->Height=PropertyViewModel->LineHeight;
            ComboBoxIcon->Image=
                REditorDefaultPackage::Get()->GetIcon(U"CodiconChevronDown");

            Name->Anchor.RightReference=ComboBoxIcon;
            Name->Anchor.RightOffset=5;
            Name->Anchor.RightReferenceEdge=EHorizontalWidgetEdge::Left;

            auto Mouse=NewWidget<RMouseWidget>(Value);
            Mouse->Anchor.Fill(Value);
            Mouse->OnClicked.BindLambda([this,i,ValueWeak](const SMouseButtonEvent&)
            {
                //open asset selector
                SIntPoint PopupSize;
                PopupSize.X=300;
                PopupSize.Y=400;
                auto SelectorParent=REditorWindowGroupView::Get()->CreatePopupMenu(
                    PopupSize
                    ,ValueWeak
                );

                auto Selector=NewWidget<REditorAssetSelectorWidget>(SelectorParent);
                Selector->Anchor.Fill(SelectorParent);
                Selector->OnAssetSelected.Bind([this,i](TSharedObjectPtr<RObject> Material)
                {
                    PropertyViewModel->SetMaterialValue(i,Material);
                });
                Selector->SetAssetType(EEditorSelectableAssetType::Material);

                return true;
            });

        }
        else if(PropertyType == REditorReflectedPropertyViewModel::EPropertyType::Vector)
        {
            auto Value=NewWidget<RTextWidget>(ValueParent);
            Value->Anchor.Fill(ValueParent);
            Value->Text=[this,i]()->CString
            {
                return U"大小: "+CString(PropertyViewModel->GetSubNodeNum(i));
            };

            //add some opetions to change the vector
            auto MoreButton=NewWidget<RRectangleWidget>(ValueParent);
            MoreButton->Width=PropertyViewModel->LineHeight;
            MoreButton->Height=PropertyViewModel->LineHeight;
            MoreButton->Anchor.VerticalCenterReference=ValueParent;
            MoreButton->Anchor.RightReference=ValueParent;
            MoreButton->Anchor.RightOffset=2;
            MoreButton->Radius=4;
            MoreButton->FillColor=REditor::Get()->CurrentTheme->ImageButtonHovorColor;

            auto MoreButtonImage=NewWidget<RImageWidget>(MoreButton);
            MoreButtonImage->Width=PropertyViewModel->LineHeight;
            MoreButtonImage->Height=PropertyViewModel->LineHeight;
            MoreButtonImage->Image= REditorDefaultPackage::Get()->
                GetIcon(U"CodiconEllipsis");
            MoreButtonImage->Anchor.CenterIn(MoreButton);

            auto MoreButtonMouse=NewWidget<RMouseWidget>(MoreButton);
            MoreButtonMouse->Anchor.Fill(MoreButton);
            RMouseWidgetWeakPtr MoreButtonMouseWeak=MoreButtonMouse;
            MoreButton->Fill=[MoreButtonMouseWeak](){
                return MoreButtonMouseWeak->IsHovered();
            };
            MoreButtonMouse->OnClicked.BindLambda([this,MoreButtonMouseWeak,i](const SMouseButtonEvent& InEvent){
                //create a context menu
                TVector<SEditorContextMenuLine> RootContextMenu;

                //add item
                {
                    auto& Add= RootContextMenu.Emplace();
                    Add.Text=U"增加元素";
                    Add.OnClicked.Bind([this,i](){
                        PropertyViewModel->AddVectorItem(i);
                    });
                }

                //clear items
                {
                    auto& Clear= RootContextMenu.Emplace();
                    Clear.Text=U"清空";
                    Clear.OnClicked.Bind([this,i](){
                        //clear all items
                        PropertyViewModel->ClearVector(i);
                    });
                }
            
                REditorWindowGroupViewModel::Get()->ShowContextMenu(
                RootContextMenu
                ,MoreButtonMouseWeak
                ,150
                );

                return true;

            });
        }


    };


}
